package com.elitesland.system.service.impl;

import com.elitesland.core.base.PagingVO;
import com.elitesland.system.annotation.SysCode;
import com.elitesland.system.service.SysUdcProxyService;
import com.elitesland.system.service.SysUdcService;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <pre>
 * [功能说明]
 * </pre>
 *
 * @author Mir
 * @date 2020/7/31
 */
@Service
@RequiredArgsConstructor
public class SysUdcProxyServiceImpl implements SysUdcProxyService {

    private final SysUdcService sysUdcService;

    @Override
    public Object translate(Object result) {
        if (result != null) {
            try {
                boolean isTranslated = false;

                //PagingVO翻译
                if (result instanceof PagingVO) {
                    val resultList = (PagingVO<?>) result;
                    for (int i = 0; i < resultList.getRecords().size(); i++) {
                        Object oi = resultList.getRecords().get(i);
                        doTranslate(oi);
                    }
                    isTranslated = true;
                }

                //列表翻译
                if (result instanceof List) {
                    val resultList = (List<?>) result;
                    for (Object o : resultList) {
                        doTranslate(o);
                    }
                    isTranslated = true;
                }

                //Optional翻译
                if (result instanceof Optional) {
                    Object o = null;

                    val r = (Optional) result;
                    if (r.isPresent()) {
                        o = r.get();
                    }

                    if (o != null) {
                        doTranslate(o);
                        result = Optional.of(o);
                        isTranslated = true;
                    }
                }

                if (!isTranslated) {
                    doTranslate(result);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return result;
    }

    private void doTranslate(Object oi) throws InvocationTargetException, IllegalAccessException {
        Class<?> c = oi.getClass();
        Class<?>[] types = {String.class};
        val fieldNames = Arrays.stream(c.getDeclaredFields()).map(Field::getName).collect(Collectors.toList());
        for (Field field : c.getDeclaredFields()) {

            if (field.getType() == List.class) {
                try {
                    val m = c.getMethod("get" + StringUtils.capitalize(field.getName()));

                    val listValues = (List<?>) m.invoke(oi);
                    if (listValues != null && !listValues.isEmpty()) {
                        listValues.forEach(lv -> {
                            try {
                                doTranslate(lv);
                            } catch (InvocationTargetException | IllegalAccessException ignored) {
                            }
                        });
                    }

                } catch (NoSuchMethodException ignored) {
                }
            }

            if (field.getType() != String.class && field.isAnnotationPresent(SysCode.class)) {
                try {
                    val getter = c.getMethod("get" + StringUtils.capitalize(field.getName()));
                    val o = getter.invoke(oi);

                    translate(o);
                } catch (NoSuchMethodException ignored) {
                }
            }

            if (field.isAnnotationPresent(SysCode.class)) {
                if (fieldNames.contains(field.getName() + "Name")) {
                    try {
                        val anno = field.getAnnotation(SysCode.class);
                        val codeMap = sysUdcService.getCodeMap(anno.sys(), anno.mod());

                        val fieldMethodName = StringUtils.capitalize(field.getName());
                        val getter = c.getMethod("get" + fieldMethodName);
                        String code = (String) getter.invoke(oi);
                        val desc = codeMap.getOrDefault(code, "");
                        val m = c.getMethod("set" + fieldMethodName + "Name", types);
                        m.invoke(oi, desc);
                    } catch (NoSuchMethodException ignored) {
                    }
                }
            }
        }
    }
}
